-
Notifications
You must be signed in to change notification settings - Fork 534
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move PolyBFT to Edge #774
Move PolyBFT to Edge #774
Conversation
CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅ |
I have read the CLA Document and I hereby sign the CLA |
I have read the CLA Document and I hereby sign the CLA |
I have read the CLA Document and I hereby sign the CLA |
b921707
to
3166299
Compare
81e8324
to
3794de4
Compare
Codecov Report
@@ Coverage Diff @@
## feature/v3-parity #774 +/- ##
=====================================================
- Coverage 52.42% 46.64% -5.78%
=====================================================
Files 132 156 +24
Lines 17478 20472 +2994
=====================================================
+ Hits 9162 9549 +387
- Misses 7651 10236 +2585
- Partials 665 687 +22
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
3392fd1
to
5f97c5e
Compare
|
||
defer newBlockSub.Close() | ||
|
||
SYNC: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be using goto
directives in Go in 2022, because we couldn't figure out how to write the program flow better.
Please refactor this method flow to not rely on goto label directives.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cc @ferranbt, wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't be using goto directives in Go in 2022, because we couldn't figure out how to write the program flow better.
I do not think we can generalize on the use of goto
. Though I agree that It should not be used as a replacement for control loops, I think there are specific use cases where it is beneficial and we should not automatically discard it because of historical reasons (Note that many other projects from Hashicorp, Kubernetes, and Golang lang itself use goto
statements as well).
I would prefer if your concern is about how goto
is not being used correctly here and proposals to change the logic instead of an automatic discard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, if you feel strongly about this we can bring this topic on the code quality session and add it as part of the code guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be solved case by case, it's still in use yes https://github.com/hashicorp/raft/search?q=goto but agree should be used with care, I expressed the same concern a while ago.
func (p *Polybft) isSynced() bool { | ||
// TODO: Check could we change following condition to this: | ||
// p.syncer.GetSyncProgression().CurrentBlock >= p.syncer.GetSyncProgression().HighestBlock | ||
syncProgression := p.syncer.GetSyncProgression() | ||
|
||
return syncProgression == nil || | ||
p.blockchain.CurrentHeader().Number >= syncProgression.HighestBlock | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think you can rely on sync progression, because the syncing mechanism is always on and always syncing blocks
cc @dbrajovic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a requirement for the integration with pbft-consensus
. It is expected that the sync protocol is always syncing blocks.
select { | ||
case <-p.closeCh: | ||
return false | ||
case <-time.After(2 * time.Second): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How did you come up with this 2s
value?
numPeers := len(p.config.Network.Peers()) | ||
if numPeers >= minSyncPeers { | ||
break | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will break single node networks. Please remove this condition, or make minSyncPeers
variable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was made for testing so that we could skip the first Round Change when the network was initializing.
What is the use case of running a single-node network of an instant finally consensus protocol?
func (p *Polybft) verifyHeaderImpl(parent, header *types.Header, parents []*types.Header) error { | ||
blockNumber := header.Number | ||
if blockNumber == 0 { | ||
// TODO: Remove, this was just for simplicity since I had started the chain already, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
if !p.isSynced() { | ||
// we are currently syncing new data, for sure we are stuck. | ||
// We can return 0 here at least for now since that value is only used | ||
// for the open telemetry tracing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Comments should not end with periods
} | ||
|
||
// Now, we have to check if the current value of the round 'num' is lower | ||
// than our currently synced block. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Comments should not end with periods
currentHeader := p.blockchain.CurrentHeader().Number | ||
if currentHeader > num { | ||
// at this point, it will exit the sync process and start the fsm round again | ||
// (or sync a small number of blocks) to start from the correct position. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: Comments should not end with periods
Sender ethgo.Address | ||
// Target is the decoded 'target' field from the event | ||
Target ethgo.Address |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the types.Address
type
// Data is the decoded 'data' field from the event | ||
Data []byte | ||
// Log contains raw data about smart contract event execution | ||
Log *ethgo.Log |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the default log type instead of ethgo.Log
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We rely on Tracker
from the ethgo
library for tracking events emitted on the rootchain and it provides us ethgo.Log
objects (since it doesn't know for types.Log
from the Edge codebase). Therefore unsure whether it is feasible to make such change (I mean we could, but we would need to have conversion from one to another type implemented somewhere and doesn't seem like beneficial, because we couldn't get rid of etgo.Log
completely).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree with Stefan.
id, ok := raw["id"].(*big.Int) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to decode id field of log: %+v", log) | ||
} | ||
|
||
sender, ok := raw["sender"].(ethgo.Address) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to decode sender field of log: %+v", log) | ||
} | ||
|
||
target, ok := raw["target"].(ethgo.Address) | ||
if !ok { | ||
return nil, fmt.Errorf("failed to decode target field of log: %+v", log) | ||
} | ||
|
||
data, ok := raw["data"].([]byte) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please extract out these map keys to constants?
// paired list | ||
keys := make([][]byte, 0) | ||
values := make([][]byte, 0) | ||
if numberOfSnapshotsToLeaveInDB > 0 { // TODO this is always true?! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
@@ -0,0 +1,538 @@ | |||
package polybft |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please standardize all the errors in this file, there is no need to use fmt.Errorf
everywhere
@@ -0,0 +1,33 @@ | |||
package polybft |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename this file to to include the _test
prefix, as it doesn't need to be compiled into the final binary
cc @vcastellm
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed through #825
"github.com/hashicorp/go-hclog" | ||
) | ||
|
||
// TODO: Should we switch validators snapshot to Edge implementation? (validators/store/snapshot/snapshot.go) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leftover?
…lygon/polygon-edge into feature/EVM_44_Move_Polybft_to_Edge
func (v validatorSet) CalcProposer(round uint64) pbft.NodeID { | ||
var seed uint64 | ||
if v.last == (types.Address{}) { | ||
seed = round | ||
} else { | ||
offset := 0 | ||
if indx := v.validators.Index(v.last); indx != -1 { | ||
offset = indx | ||
} | ||
|
||
seed = uint64(offset) + round + 1 | ||
} | ||
|
||
pick := seed % uint64(v.validators.Len()) | ||
|
||
return pbft.NodeID(v.validators[pick].Address.String()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not very truthful, if validators are simply appended to the end of the validator set. Validators that are added to the end can get the chance to propose the block before some other nodes which were next in line.
Example:
- Validators are A, B, C
- Block 0 is proposed by A, block 1 by B, block 2 by C
- When C is the proposer, a new validator is added to the end (D)
- The proposer for block 3 should've been A, but from this method it's D (which is unfair to A)
- Validator D should've been the proposer in the next round of proposals, not the current one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not very truthful
As with the validator uptime comment. I think it is hard to come up with a silver bullet strategy for every piece of consensus logic. This in particular is based on the Tendermint proposer calculation which improves some of the security problems in Round Robin for public networks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've left extensive comments on this PR because I believe we need to address and discuss some things which can cause major problems in the future. Code style is completely inconsistent. The vast, vast majority of functionality is not covered with tests.
Please resolve the comments, and we can see where to go from there 🙏
Description
Pbft consensus engine together with polybft consensus protocol is introduced with this PR.
Transfer (without transactions processing) polybft including pbft consensus from v3 client to Polygon Edge: https://polygon.atlassian.net/browse/EVM-44
Commands to run
Compile smart contracts:
cd consensus/polybft/polybftcontracts && npm install && npm run compile
Init accounts:
go run main.go polybft-secrets --data-dir test-chain- --num 4
Init genesis:
go run main.go genesis-polybft --block-gas-limit 10000000 --validator-set-size=4
Run nodes:
Changes include
Checklist
Testing